from rest_framework import serializers
from orders.models import OrdersModel
from django_redis import get_redis_connection
from django.db import transaction
import datetime
from course.models import CourseModel
from coupon.models import CouponModel,CouponLogModel
from orders.models import OrderDetaileModel
from fuguangeduapi.utils import constants
class OrderModelSerializers(serializers.ModelSerializer):
    user_coupon_id = serializers.IntegerField(write_only=True,default=None)
    class Meta:
        model = OrdersModel
        fields = ['pay_type','id','user_coupon_id','credit']
        extra_kwargs = {
            "pay_type":{"write_only":True},
            "credit":{"write_only":True},
        }
    def create(self, validated_data):
        # 往订单中添加新订单
        # 用户
        user = self.context['request'].user
        user_id = user.id
        # 购买课程----获取购物车中的课程
        redis = get_redis_connection('cart')
        # 获取当前用户课程列表
        cart_hash = redis.hgetall(f"cart_{user_id}")
        if len(cart_hash)<1:
            raise serializers.ValidationError(detail='购物车没有数据',code="cart_empty")
        # 获取前端传递的使用积分
        use_credit = int(validated_data.get('credit',0))
        # 判断当前用户是否选择积分，且积分是否足够划扣
        if use_credit>0 and use_credit>user.credit:
            raise serializers.ValidationError(detail='您的积分不足够划扣，请重新选择',code='credit_error')
        # 获取前端传递的优惠劵id
        user_coupon_id = validated_data.get('user_coupon_id', None)
        user_coupons = None
        # 如果前端传递了优惠劵id，且不为空，获取优惠劵信息
        if user_coupon_id is not None:
            user_coupons = CouponLogModel.objects.filter(id=user_coupon_id, user_id=user_id).first()
        # 开启数据库操作   事务
        # 原子性   一致性    隔离性   持久性
        with transaction.atomic():
            # 创建一个还原点
            t1 = transaction.savepoint()
            try:
                # 创建订单，获取订单对象，存，并获得模型对象
                orders = OrdersModel.objects.create(
                    name='浮光商城课程购买订单',
                    user_id=user_id,
                    #  基于redis生成分布式得唯一订单号
                    order_number= datetime.datetime.now().strftime("%Y%m%d")+("%08d" % user_id)+"%08d" % redis.incr("order_number"),
                    pay_type=validated_data.get('pay_type'),
                )
                # 订单记录表创建完成，获取课程列表，生成订单详情数据，并外键添加
                # 在获取到课程列表情况下，通过循环课程列表，计算：所有课程可用积分
                # 最优优惠券，
                # 订单总价 、  优惠活动得优惠价格
                # 课程总价
                course_id_list = [int(key.decode()) for key,value in cart_hash.items() if value==b'1']
                #  根据选中购物车列表中得id结果集，获取数据库中对应课程列表
                course_list = CourseModel.objects.filter(id__in=course_id_list,is_deleted=False,is_show=True)
                # 订单总价
                total_price = 0  # 本次所有商品/课程的总价
                real_price = 0   # 本次订单实付金额，优惠后的价格
                max_discount_course = None   # 最优课程
                # 积分--计算最多可以抵扣积分
                max_use_credit = 0  # 本次下单，最多可以抵扣的积分
                total_discount_price = 0  # 最终折扣价格

                # 构建一个空列表，用于存放订单列表
                data_list = []
              # 循环课程，统计价格，优惠相关信息，生成订单
                for course in course_list:
                    # 获取当前课程优惠价格，如果没有优惠价格，则赋值课程原价
                    discount_price = course.discount.get('price',course.price)
                    discount_name = course.discount.get('type',"")
                    # 创建订单详情表    没有执行save    没执行crete
                    data_list.append(OrderDetaileModel(
                        order=orders,
                        course=course,
                        discount_name=discount_name,
                        price=course.price,
                        real_price=discount_price,
                    ))
                    # 循环，计算课程的总价和实际付款价格
                    total_price += float(course.price)
                    # 循环，计算课程优惠价格
                    real_price += float(discount_price)
                    # 找到最优课程，优惠券
                    if user_coupons:
                        # 判断当前最优惠课程，是否有数据，没有默认赋值当前循环的课程
                        if max_discount_course is None:
                            max_discount_course = course
                        else:
                            # 判断当前循环的课程价格，是否大于已经存在的最优惠的课程的价格
                            # 价格越高，使用优惠更优惠
                            if course.price >= max_discount_course.price:
                                max_discount_course = course
                     # 积分   每个课程的积分，循环相加
                    if use_credit > 0 and course.credit > 0:
                        # 循环课程，获取最大可以使用积分
                        max_use_credit += course.credit
                # 往数据库中，添加订单详情列表数据
                OrderDetaileModel.objects.bulk_create(data_list)
                # 计算最终优惠价格
                # 优惠劵  或者是积分
                if user_coupons:
                    # 拿到优惠劵   优惠公式  -100   *0.8
                    sale = user_coupons.coupon.sale[1:]
                    if user_coupons.coupon.discount == 1:
                        # 减免优惠劵
                        total_discount_price = float(sale)
                    elif user_coupons.coupon.discount == 2:
                        total_discount_price = float(float(max_discount_course.price)*(1-float(sale)))
                # 积分
                if use_credit > 0:
                    if max_use_credit < use_credit:
                        raise serializers.ValidationError(detail='超过当前最大可用积分限制',code='credit_max')
                    # 给订单记录表赋值
                    orders.credit = use_credit
                    # 把积分换成钱
                    total_discount_price = float(use_credit/constants.CREDIT_TO_MONEY)
                    # 扣除用户得最终积分
                    user.credit = user.credit - use_credit
                    user.save()
                # 给订单列表赋值，课程总价  实际付款金额
                orders.total_price = total_price
                orders.real_price = float(real_price) - float(total_discount_price)
                orders.save()
                # 删除购物车中的数据
                cart = {key:value for key,value in cart_hash.items() if value == b'0'}
                # 删除redis中购物车所有关于当前用户的数据
                pipe = redis.pipeline()
                pipe.multi()
                pipe.delete(f"cart_{user_id}")
                if len(cart)>0:
                    pipe.hset(f"cart_{user_id}",mapping=cart)
                pipe.execute()
                # 优惠劵id直接获取优惠劵对象，获取优惠劵日志管理类对象
                if user_coupons:
                    # 将优惠劵，绑定都订单中
                    user_coupons.order = orders
                    redis = get_redis_connection('coupon')
                    redis.delete(f'{user_id}:{user_coupon_id}')
                    # 返回订单对象
                return orders



                # 优惠劵操作
                # 积分计算
                # redis处理
                # 购物车、优惠劵

            except Exception as es:
                print('订单创建失败----')
                print(es)
                transaction.savepoint_rollback(t1)
                raise serializers.ValidationError(detail='订单生成失败',code='order_error')

class OrderDetailModelSerializer(serializers.ModelSerializer):
    course_id = serializers.IntegerField(source='course.id')
    course_name = serializers.CharField(source='course.name')
    course_cover = serializers.ImageField(source='course.course_cover')
    class Meta:
        model = OrderDetaileModel
        fields =['id','price','real_price','discount_name','course_id','course_name','course_cover']
# 订单列表序列化器
class OrderListModelSerializer(serializers.ModelSerializer):
    # 嵌套序列化
    order_course = OrderDetailModelSerializer(many=True)
    # 优惠劵信息
    class Meta:
        model = OrdersModel
        fields = ['id','order_number','total_price','order_status','real_price','pay_time','pay_type','credit','order_course','created_time','coupon']



















